﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq.Expressions;
using System.Text;

namespace GodReply.ORM
{
    public abstract partial class DbContext : DbAccessory, IDisposable
    {

        #region Constructor
        public DbContext(ConnectionConfig config)
        {
            base.CurrentConnectionConfig = config;
            //if (config.DbType == DbType.Oracle)
            //{
            //    throw new Exception("Oracle developed 60%,to be continued ");
            //}
        }
        #endregion

        #region  ADO Methods
        /// <summary>
        ///Database operation
        /// </summary>
        public virtual IAdo Ado
        {
            get
            {
                if (_Ado == null)
                {
                    var reval = InstanceFactory.GetAdo(base.CurrentConnectionConfig);
                    //Check.ConnectionConfig(base.CurrentConnectionConfig);
                    _Ado = reval;
                    //reval.Context = this;
                    return reval;
                }
                return _Ado;
            }
        }
        #endregion

        bool _disposed = false;

        //Dictionary<Type, TrackEntityCollection> _trackingEntityContainer;

        //Dictionary<Type, TrackEntityCollection> TrackingEntityContainer
        //{
        //    get
        //    {
        //        if (this._trackingEntityContainer == null)
        //        {
        //            this._trackingEntityContainer = new Dictionary<Type, TrackEntityCollection>();
        //        }

        //        return this._trackingEntityContainer;
        //    }
        //}


        protected virtual void Dispose(bool disposing)
        {

        }
        public void Dispose()
        {
            if (this._disposed)
                return;

            this.Dispose(true);
            this._disposed = true;
        }

        //public virtual IEnumerable<T> SqlQuery<T>(string sql, params DbParam[] parameters)
        //{
        //    return this.SqlQuery<T>(sql, CommandType.Text, parameters);
        //}

        //public virtual IEnumerable<T> SqlQuery<T>(string sql, CommandType cmdType, params DbParam[] parameters)
        //{
        //    Utils.CheckNull(sql, "sql");
        //    return new InternalSqlQuery<T>(this, sql, cmdType, parameters);
        //}

        public virtual IQuery<TEntity> Query<TEntity>()
        {
            return this.Query<TEntity>(null);
        }

        public virtual IQuery<TEntity> Query<TEntity>(string table)
        {
            return new Query<TEntity>(this, table);
        }

        //public virtual TEntity Insert<TEntity>(TEntity entity)
        //{
        //    return this.Insert(entity, null);
        //}

        //public virtual TEntity Insert<TEntity>(TEntity entity, string table)
        //{
        //    Utils.CheckNull(entity);

        //    TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(entity.GetType());

        //    Dictionary<MappingMemberDescriptor, object> keyValueMap = CreateKeyValueMap(typeDescriptor);
        //    MappingMemberDescriptor autoIncrementMemberDescriptor = typeDescriptor.AutoIncrement;

        //    Dictionary<MappingMemberDescriptor, DbExpression> insertColumns = new Dictionary<MappingMemberDescriptor, DbExpression>();
        //    foreach (var kv in typeDescriptor.MappingMemberDescriptors)
        //    {
        //        MappingMemberDescriptor memberDescriptor = kv.Value;

        //        if (memberDescriptor == autoIncrementMemberDescriptor)
        //            continue;

        //        object val = memberDescriptor.GetValue(entity);

        //        if (keyValueMap.ContainsKey(memberDescriptor))
        //        {
        //            keyValueMap[memberDescriptor] = val;
        //        }

        //        DbExpression valExp = DbExpression.Parameter(val, memberDescriptor.MemberInfoType);
        //        insertColumns.Add(memberDescriptor, valExp);
        //    }

        //    MappingMemberDescriptor nullValueKey = keyValueMap.Where(a => a.Value == null && a.Key != autoIncrementMemberDescriptor).Select(a => a.Key).FirstOrDefault();
        //    if (nullValueKey != null)
        //    {
        //        /* 主键为空并且主键又不是自增列 */
        //        throw new ChloeException(string.Format("The primary key '{0}' could not be null.", nullValueKey.MemberInfo.Name));
        //    }

        //    DbTable dbTable = table == null ? typeDescriptor.Table : new DbTable(table, typeDescriptor.Table.Schema);
        //    DbInsertExpression e = new DbInsertExpression(dbTable);

        //    foreach (var kv in insertColumns)
        //    {
        //        e.InsertColumns.Add(kv.Key.Column, kv.Value);
        //    }

        //    if (autoIncrementMemberDescriptor == null)
        //    {
        //        this.ExecuteSqlCommand(e);
        //        return entity;
        //    }

        //    IDbExpressionTranslator translator = this.DbContextServiceProvider.CreateDbExpressionTranslator();
        //    List<DbParam> parameters;
        //    string sql = translator.Translate(e, out parameters);

        //    sql = string.Concat(sql, ";", this.GetSelectLastInsertIdClause());

        //    //SELECT @@IDENTITY 返回的是 decimal 类型
        //    object retIdentity = this.Session.ExecuteScalar(sql, parameters.ToArray());

        //    if (retIdentity == null || retIdentity == DBNull.Value)
        //    {
        //        throw new ChloeException("Unable to get the identity value.");
        //    }

        //    retIdentity = ConvertIdentityType(retIdentity, autoIncrementMemberDescriptor.MemberInfoType);
        //    autoIncrementMemberDescriptor.SetValue(entity, retIdentity);
        //    return entity;
        //}

        //public virtual object Insert<TEntity>(Expression<Func<TEntity>> content)
        //{
        //    return this.Insert(content, null);
        //}

        //public virtual object Insert<TEntity>(Expression<Func<TEntity>> content, string table)
        //{
        //    Utils.CheckNull(content);

        //    TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(typeof(TEntity));

        //    if (typeDescriptor.PrimaryKeys.Count > 1)
        //    {
        //        /* 对于多主键的实体，暂时不支持调用这个方法进行插入 */
        //        throw new NotSupportedException(string.Format("Can not call this method because entity '{0}' has multiple keys.", typeDescriptor.EntityType.FullName));
        //    }

        //    MappingMemberDescriptor keyMemberDescriptor = typeDescriptor.PrimaryKeys.FirstOrDefault();
        //    MappingMemberDescriptor autoIncrementMemberDescriptor = typeDescriptor.AutoIncrement;

        //    Dictionary<MemberInfo, Expression> insertColumns = InitMemberExtractor.Extract(content);

        //    DbTable explicitDbTable = null;
        //    if (table != null)
        //        explicitDbTable = new DbTable(table, typeDescriptor.Table.Schema);
        //    DefaultExpressionParser expressionParser = typeDescriptor.GetExpressionParser(explicitDbTable);
        //    DbInsertExpression e = new DbInsertExpression(explicitDbTable ?? typeDescriptor.Table);

        //    object keyVal = null;

        //    foreach (var kv in insertColumns)
        //    {
        //        MemberInfo key = kv.Key;
        //        MappingMemberDescriptor memberDescriptor = typeDescriptor.TryGetMappingMemberDescriptor(key);

        //        if (memberDescriptor == null)
        //            throw new ChloeException(string.Format("The member '{0}' does not map any column.", key.Name));

        //        if (memberDescriptor == autoIncrementMemberDescriptor)
        //            throw new ChloeException(string.Format("Could not insert value into the identity column '{0}'.", memberDescriptor.Column.Name));

        //        if (memberDescriptor.IsPrimaryKey)
        //        {
        //            object val = ExpressionEvaluator.Evaluate(kv.Value);
        //            if (val == null)
        //                throw new ChloeException(string.Format("The primary key '{0}' could not be null.", memberDescriptor.MemberInfo.Name));
        //            else
        //            {
        //                keyVal = val;
        //                e.InsertColumns.Add(memberDescriptor.Column, DbExpression.Parameter(keyVal));
        //                continue;
        //            }
        //        }

        //        e.InsertColumns.Add(memberDescriptor.Column, expressionParser.Parse(kv.Value));
        //    }

        //    if (keyMemberDescriptor != null)
        //    {
        //        //主键为空并且主键又不是自增列
        //        if (keyVal == null && keyMemberDescriptor != autoIncrementMemberDescriptor)
        //        {
        //            throw new ChloeException(string.Format("The primary key '{0}' could not be null.", keyMemberDescriptor.MemberInfo.Name));
        //        }
        //    }

        //    if (keyMemberDescriptor == null || keyMemberDescriptor != autoIncrementMemberDescriptor)
        //    {
        //        this.ExecuteSqlCommand(e);
        //        return keyVal; /* It will return null if an entity does not define primary key. */
        //    }

        //    IDbExpressionTranslator translator = this.DbContextServiceProvider.CreateDbExpressionTranslator();
        //    List<DbParam> parameters;
        //    string sql = translator.Translate(e, out parameters);
        //    sql = string.Concat(sql, ";", this.GetSelectLastInsertIdClause());

        //    //SELECT @@IDENTITY 返回的是 decimal 类型
        //    object retIdentity = this.Session.ExecuteScalar(sql, parameters.ToArray());

        //    if (retIdentity == null || retIdentity == DBNull.Value)
        //    {
        //        throw new ChloeException("Unable to get the identity value.");
        //    }

        //    retIdentity = ConvertIdentityType(retIdentity, autoIncrementMemberDescriptor.MemberInfoType);
        //    return retIdentity;
        //}

        //public virtual int Update<TEntity>(TEntity entity)
        //{
        //    return this.Update(entity, null);
        //}

        //public virtual int Update<TEntity>(TEntity entity, string table)
        //{
        //    Utils.CheckNull(entity);

        //    TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(entity.GetType());
        //    EnsureEntityHasPrimaryKey(typeDescriptor);

        //    Dictionary<MappingMemberDescriptor, object> keyValueMap = CreateKeyValueMap(typeDescriptor);

        //    IEntityState entityState = this.TryGetTrackedEntityState(entity);
        //    Dictionary<MappingMemberDescriptor, DbExpression> updateColumns = new Dictionary<MappingMemberDescriptor, DbExpression>();
        //    foreach (var kv in typeDescriptor.MappingMemberDescriptors)
        //    {
        //        MemberInfo member = kv.Key;
        //        MappingMemberDescriptor memberDescriptor = kv.Value;

        //        if (keyValueMap.ContainsKey(memberDescriptor))
        //        {
        //            keyValueMap[memberDescriptor] = memberDescriptor.GetValue(entity);
        //            continue;
        //        }

        //        if (memberDescriptor.IsAutoIncrement)
        //            continue;

        //        object val = memberDescriptor.GetValue(entity);

        //        if (entityState != null && !entityState.HasChanged(memberDescriptor, val))
        //            continue;

        //        DbExpression valExp = DbExpression.Parameter(val, memberDescriptor.MemberInfoType);
        //        updateColumns.Add(memberDescriptor, valExp);
        //    }

        //    if (updateColumns.Count == 0)
        //        return 0;

        //    DbTable dbTable = table == null ? typeDescriptor.Table : new DbTable(table, typeDescriptor.Table.Schema);
        //    DbExpression conditionExp = MakeCondition(keyValueMap, dbTable);
        //    DbUpdateExpression e = new DbUpdateExpression(dbTable, conditionExp);

        //    foreach (var item in updateColumns)
        //    {
        //        e.UpdateColumns.Add(item.Key.Column, item.Value);
        //    }

        //    int ret = this.ExecuteSqlCommand(e);
        //    if (entityState != null)
        //        entityState.Refresh();
        //    return ret;
        //}

        //public virtual int Update<TEntity>(Expression<Func<TEntity, bool>> condition, Expression<Func<TEntity, TEntity>> content)
        //{
        //    return this.Update(condition, content, null);
        //}

        //public virtual int Update<TEntity>(Expression<Func<TEntity, bool>> condition, Expression<Func<TEntity, TEntity>> content, string table)
        //{

        //    {
        //        return this.Update(condition, content, null);
        //    }
        //public virtual int Update<TEntity>(Expression<Func<TEntity, bool>> condition, Expression<Func<TEntity, TEntity>> content, string table)
        //{
        //    Utils.CheckNull(condition);
        //    Utils.CheckNull(content);

        //    TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(typeof(TEntity));

        //    Dictionary<MemberInfo, Expression> updateColumns = InitMemberExtractor.Extract(content);

        //    DbTable explicitDbTable = null;
        //    if (table != null)
        //        explicitDbTable = new DbTable(table, typeDescriptor.Table.Schema);
        //    DefaultExpressionParser expressionParser = typeDescriptor.GetExpressionParser(explicitDbTable);

        //    DbExpression conditionExp = expressionParser.ParseFilterPredicate(condition);

        //    DbUpdateExpression e = new DbUpdateExpression(explicitDbTable ?? typeDescriptor.Table, conditionExp);

        //    foreach (var kv in updateColumns)
        //    {
        //        MemberInfo key = kv.Key;
        //        MappingMemberDescriptor memberDescriptor = typeDescriptor.TryGetMappingMemberDescriptor(key);

        //        if (memberDescriptor == null)
        //            throw new ChloeException(string.Format("The member '{0}' does not map any column.", key.Name));

        //        if (memberDescriptor.IsPrimaryKey)
        //            throw new ChloeException(string.Format("Could not update the primary key '{0}'.", memberDescriptor.Column.Name));

        //        if (memberDescriptor.IsAutoIncrement)
        //            throw new ChloeException(string.Format("Could not update the identity column '{0}'.", memberDescriptor.Column.Name));

        //        e.UpdateColumns.Add(memberDescriptor.Column, expressionParser.Parse(kv.Value));
        //    }

        //    if (e.UpdateColumns.Count == 0)
        //        return 0;

        //    return this.ExecuteSqlCommand(e);
        //}

        //public virtual int Delete<TEntity>(TEntity entity)
        //{
        //    return this.Delete(entity, null);
        //}

        //public virtual int Delete<TEntity>(TEntity entity, string table)
        //{
        //    Utils.CheckNull(entity);

        //    TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(entity.GetType());
        //    EnsureEntityHasPrimaryKey(typeDescriptor);

        //    Dictionary<MappingMemberDescriptor, object> keyValueMap = new Dictionary<MappingMemberDescriptor, object>();

        //    foreach (MappingMemberDescriptor keyMemberDescriptor in typeDescriptor.PrimaryKeys)
        //    {
        //        object keyVal = keyMemberDescriptor.GetValue(entity);
        //        keyValueMap.Add(keyMemberDescriptor, keyVal);
        //    }

        //    DbTable dbTable = table == null ? typeDescriptor.Table : new DbTable(table, typeDescriptor.Table.Schema);
        //    DbExpression conditionExp = MakeCondition(keyValueMap, dbTable);
        //    DbDeleteExpression e = new DbDeleteExpression(dbTable, conditionExp);
        //    return this.ExecuteSqlCommand(e);
        //}

        //public virtual int Delete<TEntity>(Expression<Func<TEntity, bool>> condition)
        //{
        //    return this.Delete(condition, null);
        //}

        //public virtual int Delete<TEntity>(Expression<Func<TEntity, bool>> condition, string table)
        //{
        //    Utils.CheckNull(condition);

        //    TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(typeof(TEntity));

        //    DbTable explicitDbTable = null;
        //    if (table != null)
        //        explicitDbTable = new DbTable(table, typeDescriptor.Table.Schema);
        //    DefaultExpressionParser expressionParser = typeDescriptor.GetExpressionParser(explicitDbTable);
        //    DbExpression conditionExp = expressionParser.ParseFilterPredicate(condition);

        //    DbDeleteExpression e = new DbDeleteExpression(explicitDbTable ?? typeDescriptor.Table, conditionExp);

        //    return this.ExecuteSqlCommand(e);
        //}

        //public virtual int Delete<TEntity>(object key)
        //{
        //    return this.DeleteByKey<TEntity>(key, null);
        //}

        //public virtual int Delete<TEntity>(object key, string table)
        //{
        //    Expression<Func<TEntity, bool>> predicate = BuildPredicate<TEntity>(key);
        //    return this.Delete<TEntity>(predicate, table);
        //}

        //public virtual void TrackEntity(object entity)
        //{
        //    Utils.CheckNull(entity);
        //    Type entityType = entity.GetType();

        //    if (ReflectionExtension.IsAnonymousType(entityType))
        //        return;

        //    Dictionary<Type, TrackEntityCollection> entityContainer = this.TrackingEntityContainer;

        //    TrackEntityCollection collection;
        //    if (!entityContainer.TryGetValue(entityType, out collection))
        //    {
        //        TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(entityType);

        //        if (!typeDescriptor.HasPrimaryKey())
        //            return;

        //        collection = new TrackEntityCollection(typeDescriptor);
        //        entityContainer.Add(entityType, collection);
        //    }

        //    collection.TryAddEntity(entity);
        //}

        //protected virtual string GetSelectLastInsertIdClause()
        //{
        //    return "SELECT @@IDENTITY";
        //}

        //class TrackEntityCollection
        //{
        //    public TrackEntityCollection(TypeDescriptor typeDescriptor)
        //    {
        //        this.TypeDescriptor = typeDescriptor;
        //        this.Entities = new Dictionary<object, IEntityState>(1);
        //    }
        //    public TypeDescriptor TypeDescriptor { get; private set; }
        //    public Dictionary<object, IEntityState> Entities { get; private set; }
        //    public bool TryAddEntity(object entity)
        //    {
        //        if (this.Entities.ContainsKey(entity))
        //        {
        //            return false;
        //        }

        //        IEntityState entityState = new EntityState(this.TypeDescriptor, entity);
        //        this.Entities.Add(entity, entityState);

        //        return true;
        //    }
        //    public IEntityState TryGetEntityState(object entity)
        //    {
        //        IEntityState ret;
        //        if (!this.Entities.TryGetValue(entity, out ret))
        //            ret = null;

        //        return ret;
        //    }
        //}

    }
}
